package cn.yj.core.tuodan;

import cn.yj.annotation.pagehelper.page.Page;
import cn.yj.api.FileUploadHandler;
import cn.yj.cgs.dba.entity.Customer;
import cn.yj.cgs.dba.entity.Images;
import cn.yj.cgs.dba.entity.Message;
import cn.yj.cgs.dba.entity.TuoDan;
import cn.yj.cgs.dba.mapper.CustomerMapper;
import cn.yj.cgs.dba.mapper.ImagesMapper;
import cn.yj.cgs.dba.mapper.TuoDanMapper;
import cn.yj.common.AppExecutor;
import cn.yj.common.Enums;
import cn.yj.common.ImageUtils;
import cn.yj.common.UUIdUtils;
import cn.yj.common.config.BeanTool;
import cn.yj.common.emums.PayFrom;
import cn.yj.commons.StringPools;
import cn.yj.commons.utils.ServletUtils;
import cn.yj.commons.utils.StringUtils;
import cn.yj.core.business.service.iservice.IMessageService;
import cn.yj.core.kwfilter.WordFilter;
import cn.yj.email.EmailType;
import cn.yj.email.handle.DefaultEmailHandler;
import cn.yj.email.handle.Email;
import cn.yj.entity.Base64Entity;
import cn.yj.entity.R;
import cn.yj.params.check.annotation.CheckObjectValue;
import cn.yj.params.check.annotation.KeyValue;
import cn.yj.params.check.annotation.Require;
import cn.yj.tools.exception.ServiceException;
import cn.yj.tools.readconfig.PropertiesUtils;
import cn.yj.wx.pay.enrity.Amount;
import cn.yj.wx.pay.enrity.JSAPIPayOrderResult;
import cn.yj.wx.pay.enrity.Payer;
import cn.yj.wx.pay.enrity.WechatPayRequest;
import cn.yj.wx.pay.wrapper.WechatPayExecutor;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author 永健
 * @since 2021-10-10 18:53
 */
@Service
@Transactional
public class TuoDanService extends ServiceImpl<TuoDanMapper, TuoDan> {

    @Resource
    private IMessageService messageService;

    @Resource
    private ImagesMapper imagesMapper;

    @Resource
    private CustomerMapper customerMapper;

    private static File WATER_FILE;

    static {
        WATER_FILE = new File(PropertiesUtils.getStringValue("school-cbd.water-img-path"));
    }

    /**
     * 我发布的纸条
     *
     * @param params
     * @param page
     */
    public Page<TuoDan> myPush(@Require Map<String, Object> params, @Require Page<TuoDan> page) {
        baseMapper.findList(params, page);
        List<TuoDan> rows = page.getRows();
        rows.forEach(row -> row.setImagesList(baseMapper.selectImages(row.getTuoDanCode())));
        return page;
    }

    /**
     * 我抽到的纸条
     *
     * @param userCode
     * @param page
     */
    public Page<TuoDan> myGetList(@Require String userCode, @Require Page<TuoDan> page) {
        baseMapper.myGetList(userCode, page);
        List<TuoDan> rows = page.getRows();
        rows.forEach(row -> row.setImagesList(baseMapper.selectImages(row.getTuoDanCode())));
        return page;
    }

    /**
     * 销毁
     *
     * @param code
     */
    public boolean delete(@Require String code) {
        return super.remove(new UpdateWrapper<TuoDan>().lambda().eq(TuoDan::getTuoDanCode, code));
    }

    @CheckObjectValue(keyValue = @KeyValue(type = TuoDan.class, name = {"userCode", "content", "wechatId",
            "schoolName"}))
    public R push(TuoDan tuoDan) {
        // 敏感词过滤
        Set<String> words = new WordFilter().filter_search_out_word(tuoDan.getContent());

        tuoDan.setStatus(Enums.Article.STATUS.SUCCESS.name());
        tuoDan.setTuoDanCode(UUIdUtils.getCode());

        String msg = "纸条已保存";
        if (!words.isEmpty()) {
            tuoDan.setStatus(Enums.Article.STATUS.DOING.name());
            msg = "您的内容疑似存在敏感词 [ " + StringUtils.join(words, ",") + "],文章需要审核方可通过!  请同学文明用语哦～ 否则账号会被封禁哦～";
            messageService.notice(new Message(msg, "违规提示", tuoDan.getUserCode()));

            Email email = new Email(EmailType.敏感词检测通知,
                    "用户发布脱单纸条内容，疑似存在敏感词,文章内容如下：<br/><br/>" + tuoDan.getContent() + "  " + "<br/><br/>\n " + "疑似敏感词：\n"
                            + "<br/>" + JSON.toJSONString(words));
            email.setRecEmail(email.getFrom());
            AppExecutor.exec(() -> BeanTool.getBean(DefaultEmailHandler.class).sendEmail(email));
        }
        handlerImg(tuoDan);
        Customer customer = customerMapper.selectOne(new QueryWrapper<Customer>().lambda().eq(Customer::getUserCode,
                tuoDan.getUserCode()));
        tuoDan.setAvatar(customer.getAvatar());
        tuoDan.setNickName(customer.getNickName());
        baseMapper.insert(tuoDan);
        return R.success(msg);
    }

    private void uploadImg(ImagesMapper imagesMapper, CyclicBarrier cyclicBarrier, String imgBase64, String articleNo) {
        try {
            // 水印处理
            imgBase64 = ImageUtils.addImageWaterMark(imgBase64, WATER_FILE);
        } catch (IOException e) {
            log.error("水印处理异常", e);
        }
        try {
            Base64Entity base64Entity = new Base64Entity(imgBase64,
                    Enums.Minio.Bucket.TuoDan.name().concat("/").concat(UUIdUtils.getCode().concat(StringPools.JPG)));
            base64Entity.setContentType(Enums.Minio.ContentType.IMG.getContentType());

            String upload = FileUploadHandler.getInstant().upload(base64Entity);
            Images image = new Images(Enums.Images.TYPE.TUODAN.name(), upload, articleNo);
            imagesMapper.insert(image);
            cyclicBarrier.await();
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("图片处理异常，请重试");
        }
    }

    private void handlerImg(TuoDan articleFormVo) {

        List<String> images = articleFormVo.getImages();

        if (StringUtils.isNotNull(images) && !images.isEmpty()) {
            if (images.size() > 3) {
                throw new ServiceException("最多只能上传3张图片");
            }

            ExecutorService executorService = Executors.newFixedThreadPool(images.size());
            final CyclicBarrier cyclicBarrier = new CyclicBarrier(images.size() + Enums.Common.ONE);

            // 图片上传
            images.forEach(img -> executorService.execute(() -> uploadImg(imagesMapper, cyclicBarrier, img,
                    articleFormVo.getTuoDanCode())));

            try {
                cyclicBarrier.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
            executorService.shutdown();
        }
    }

    public TuoDan random(@Require String userCode, String schoolName, @Require Integer sex) {
        List<String> tuodanCodes = baseMapper.myGetTuoDanCode(userCode);
        TuoDan tuoDan = baseMapper.selectRand(userCode, schoolName, sex, tuodanCodes.isEmpty()?null:tuodanCodes);
        if (StringUtils.isNull(tuoDan)) {
            throw new ServiceException("箱里暂时没有纸条在哦～");
        }
        String tuoDanCode = tuoDan.getTuoDanCode();
        baseMapper.saveRecord(userCode, tuoDanCode);
        tuoDan.setImagesList(baseMapper.selectImages(tuoDanCode));
        return tuoDan;
    }

    public JSAPIPayOrderResult.Payment toPayOrder(@Require String userCode,String schoolName,Integer sex, @Require String openid) throws IOException {
        // 先检查自己是否已经放了纸条
        if (baseMapper.selectCount(new QueryWrapper<TuoDan>().lambda().eq(TuoDan::getUserCode, userCode)) <= Enums.Common.ZERO) {
            throw new ServiceException("抽取纸条之前先要放取纸条哦");
        }

        List<String> tuodanCodes = baseMapper.myGetTuoDanCode(userCode);
        TuoDan tuoDan = baseMapper.selectRand(userCode, schoolName, sex, tuodanCodes.isEmpty()?null:tuodanCodes);
        if (StringUtils.isNull(tuoDan)) {
            throw new ServiceException("箱里暂时没有纸条在哦～");
        }

        WechatPayRequest wechatPayRequest = new WechatPayRequest("脱单盲盒支付-抽纸条", UUIdUtils.getCode(),
                new Amount(new BigDecimal(PropertiesUtils.getStringValue("pull.pay"))), new Payer(openid), null);
        Map<String, Object> stringStringHashMap = new HashMap<>();
        stringStringHashMap.put("device_id", ServletUtils.getRequest().getRemoteHost());
        stringStringHashMap.put("payer_client_ip", ServletUtils.getRequest().getRemoteHost());
        JSAPIPayOrderResult payOrderResult = WechatPayExecutor.getInstance().underOrderObject(PayFrom.JSAPI, wechatPayRequest);
        return payOrderResult.getPayment();
    }

    public JSAPIPayOrderResult.Payment toPayPushOrder(@Require String userCode,@Require String openid) throws IOException {
        WechatPayRequest wechatPayRequest = new WechatPayRequest("脱单盲盒支付-放纸条", UUIdUtils.getCode(),
                new Amount(new BigDecimal(PropertiesUtils.getStringValue("push.pay"))), new Payer(openid), null);
        Map<String, Object> stringStringHashMap = new HashMap<>();
        stringStringHashMap.put("device_id", ServletUtils.getRequest().getRemoteHost());
        stringStringHashMap.put("payer_client_ip", ServletUtils.getRequest().getRemoteHost());
        JSAPIPayOrderResult payOrderResult = WechatPayExecutor.getInstance().underOrderObject(PayFrom.JSAPI, wechatPayRequest);
        return payOrderResult.getPayment();
    }
}
